package com.atguigu.gmallre.mock.service.adv.impl;


import com.atguigu.mock.util.RandomNum;
import com.atguigu.gmallre.mock.factory.UserSession;
import com.atguigu.gmallre.mock.service.adv.AdvService;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.beanutils.BeanUtils;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


public class AdvServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M , T>  implements AdvService<T> {



    protected  Map<Long,T> cache=null;

    public  AdvServiceImpl(){

    }

    public  void removeWithCache(){
        remove(null);
        if(cache!=null){
            cache.clear();
        }

    }


    @PostConstruct
    protected void loadCache(){
        cache=new ConcurrentHashMap<>();
        List<T> list = list(null);
        loadCache(  list);
    }

    protected   void loadCache(List<T> list){
        for (T t : list) {
            Long id =getId(t);

            cache.put(id,t);
        }
    }

    public Map<Long,T> all(boolean  useCache){
        if(cache!=null &&cache.size()>0){
            return   cache;
        }else{
            loadCache();
            return cache;
        }
    }

    protected Long getId(T entity ){
        Long id=null;
        try {
            Field field = entity.getClass().getDeclaredField("id");
            Method method = entity.getClass().getDeclaredMethod("getId");
            id = (Long)method.invoke(entity);
            return  id;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("can't get id from the bean");
        }
    }


    public boolean saveOrUpdate(T entity, Boolean useCache) {

        saveOrUpdate(entity);
        if(cache!=null  ){
            Long id = getId(entity);
            cache.put(id ,entity);
        }
        return true;
    }

    @Override
    public boolean saveOrUpdate(T entity ) {
        fixDateTime(  entity);
        super.saveOrUpdate(entity);
        return true;
    }

    @Override
    public boolean saveOrUpdateBatch(List<T> list,int batchSize ) {
        for (T entity: list) {
            fixDateTime(  entity);
        }
        return   super.saveOrUpdateBatch(list,batchSize);
    }

    public boolean saveOrUpdateBatch(List<T> list,int batchSize, Boolean useCache) {

        saveOrUpdateBatch(list,batchSize);
        if(useCache&&cache!=null  ){
            for (T t : list) {
                Long id = getId(t);
                cache.put(id ,t);
            }
        }
        return true;
    }

    public T  getById(Long id, Boolean useCache){
        T t=null;
        if(useCache&&cache!=null  ){
             t = cache.get(id);
        }
        if(t==null ||!useCache){
             t = getById(id);
        }
        return t;
    }

    @Override
    public T getOneByRandom() {
        int size = cache.size();
        if(size>0) {
            int randInt = RandomNum.getRandInt(0, size - 1);
            Object[] objects = cache.values().toArray();
            return (T) objects[randInt];
        }else{
            return null;
        }

    }

    public  void fixDateTime(T entity){
        try {
            String id = BeanUtils.getProperty(entity, "id");
            if(id==null ){
                BeanUtils.setProperty(entity, "createTime", UserSession.getCurDateTime());
            }else{
                BeanUtils.setProperty(entity, "operateTime", UserSession.getCurDateTime());
            }
        } catch ( Exception e) {
            e.printStackTrace();
        }

    }


}
